package com.coolingme.Case;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;

/**
 * 控制反转 inversion of Control
 *
 * @author wangyue
 * @date 2019/3/16 16:55
 */
public class IOC {

    /**
     * 通过类的路径 创建对象 并返回
     *
     * @param className 类全名
     * @return 类对象
     */
    public Object getInstance(String className) {
        Object obj = null;
        // 让系统输入值，给对应的属性赋值
        System.out.println("请给" + className + "类的对象赋值");
        Scanner input = new Scanner(System.in);

        try {
            // 创建类对象
            Class clazz = Class.forName(className);
            obj = clazz.newInstance();

            // 使用自动注入DI     设置对象中的所有属性值
            // 找到每一个不同对象的所有所有set方法   给属性赋值
            // 通过拼接字符串的方式处理名字
            // 1.通过clazz找到类中的所有私有属性-->获取每一个属性的名字-->set属性
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                // 属性名
                String fieldName = field.getName();
                // 2.通过拼接字符串的形式 拼接  setName setAge
                String firstLetter = fieldName.substring(0, 1).toUpperCase();// 首字母变大写
                String otherLetters = fieldName.substring(1);// 其他字母不变
                StringBuilder setMethodName = new StringBuilder("set");
                setMethodName.append(firstLetter);
                setMethodName.append(otherLetters);

                // 3.通过方法名 和 属性类型（set方法中，参数类型必定和属性类型一致）
                // 获取属性类型
                Class fieldType = field.getType();
                Method setMethod = clazz.getMethod(setMethodName.toString(), fieldType);

                // 方法参数是在后台手动录入
                // 属性的值是使用 Scanner(文件内读取) 接收的，全是String类型
                System.out.println("请给" + fieldName + "属性赋值");
                String methodValue = input.nextLine();

                /*
                 * 将String类型转化成方法参数对应的类型
                 * 八个包装类中有七个都带有String的构造方法
                 * new Integer(String)  new Float(String) new String(String)
                 * 利用包装类自带的 String 的构造方法处理
                 * 属性类型对应的带String参数的构造方法
                 */
                Constructor con = fieldType.getConstructor(String.class);
                //con.newInstance(methodValue);     即转换后的正确的属性类型的值

                // set方法一般都是public，所以不需要强吻
                // 调用set方法     invoke(类对象，参数)
                setMethod.invoke(obj, con.newInstance(methodValue));
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

}
